package com.wontube.smr.bo.sites.vevo;

import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.wontube.client.extension.utils.DateUtils;
import com.wontube.client.extension.utils.StringUtils;
import com.wontube.core.dao.mybatis.QueryExample;
import com.wontube.core.pub.AppEnvironment;
import com.wontube.smr.bo.constants.SiteConstants;
import com.wontube.smr.client.model.po.Movie;
import com.wontube.smr.client.model.po.MovieGenre;
import com.wontube.smr.client.model.po.MovieToday;
import com.wontube.smr.client.model.po.MovieWeek;
import com.wontube.smr.client.model.po.RecentMovie;
import com.wontube.smr.dao.bo.MovieDao;
import com.wontube.smr.dao.mapper.MovieGenreMapper;
import com.wontube.smr.dao.mapper.MovieMapper;
import com.wontube.smr.dao.mapper.MovieTodayMapper;
import com.wontube.smr.dao.mapper.MovieWeekMapper;
import com.wontube.smr.dao.mapper.RecentMovieMapper;
import com.wontube.smr.pub.DefaultDBHelper;


/**
 * vevo 视频抓取
 * 
 * @author hewc@wondershare.cn
 * 
 */
public final class VevoVideoBO {
	private static final Logger logger = LoggerFactory.getLogger(VevoVideoBO.class);
	
	/**
	 * 视频地址 { "isrc":"USRV81200025", "title":"Honestly", "image_url":
	 * "http:\/\/img.cache.vevo.com\/Content\/VevoImages\/video\/5D3D6EF04BFA592
	 * 4 9 A 8 4 0 3 A 7 D 1 0 B 1 C E 3 . j p g
	 * " , "duration_in_seconds":223, "artists_main":[{"on_tour":true,"id":
	 * "b3303746-cfb2-4ddf-ac13-272e4c0a9334"
	 * ,"name":"Hot Chelle Rae","image_url":
	 * "http:\/\/img.cache.vevo.com\/Content\/VevoImages\/artist\/3833E7BC0F0524C371569F288F9D833A.jpg","url_safename":"hot-chelle-rae","f
	 * a v o r i t e c o u n t " : 6 1 , " v i d e o _ c o u n t
	 * " : 0 } ] , "artists_featured":[], "viewcount":1689450, "premiere":true ,
	 * "explicit":false, "url_safe_title":"honestly" }
	 */
	//private static final String videoUrlFormat = "http://api.vevo.com/mobile/v1/video/list.json?order={}&genres={}&offset={}&max={}";
	private static final String VIDEO_URL_FORMAT = "http://api.vevo.com/mobile/v1/video/list.json?order={}&offset={}&max=50";
	private static final String VIDEO_GENRE_URL_FORMAT = "http://api.vevo.com/mobile/v1/video/list.json?order=MostViewedAllTime&genres={}&offset={}&max=50";

	private final static String POPULAR_TODAY = "MostViewedToday";
	private final static String POPULAR_WEEK = "MostViewedThisWeek";
	private final static String POPULAR_RECENT = "mostrecent";
	private final static String POPULAR_ALL_TIME = "MostViewedAllTime";

	private final static int LIMIT = 50;
	
	
	/**
	 * grab all videos from vevo
	 * save to movie table with movie_type='Music'
	 * @return
	 */
	public static int saveAllMusicVideos(){
		int count = 0;
		int offset = 0;
		while(true){
			int saved = grabAndSaveVideos(POPULAR_ALL_TIME, offset, count);
			count += saved;
			if(saved < LIMIT){
				break;
			}
			offset += LIMIT;
		}
		
		return count;
	}	
	
	/**
	 * update video genre
	 * add or update movie_genre table, update movie table's genre field
	 * @return
	 */
	public static int updateMusicGenres(){
		int count = 0;
		for (String genre : VevoMusicGenres.getVevoInitGenres()) {			
			int offset = 0;
			while(true){
				int saved = grabAndUpdateGenres(genre, offset);
				count += saved;
				if(saved < LIMIT){
					break;
				}
				offset += LIMIT;
			}
		}		
		
		return count;
	}
	
	/**
	 * add/update to movie_today table
	 * 5页 * 50 = 250条
	 * @return
	 */
	public static int updateTodayMusics(){
		int count = 0;
		int offset = 0;
		for (int i = 0; i < 5; i++) {
			String url = StringUtils.format(VIDEO_URL_FORMAT, POPULAR_TODAY, offset);
			offset += LIMIT;
			
			//只取movie的id
			List<Movie> movies = grabVideos(url, false);
			SqlSession session = DefaultDBHelper.getBatchSqlSession();
			MovieMapper movieMapper = session.getMapper(MovieMapper.class);
			MovieTodayMapper todayMapper = session.getMapper(MovieTodayMapper.class);
			Date version = DateUtils.getNow();
			
			try {
				for (Movie movie : movies) {
					String movieId = movie.getId();
					Movie temp = movieMapper.selectByPrimaryKey(movieId);
					if(temp != null){
						QueryExample ex = new QueryExample();
						ex.or().addCriterion("movie_id=", movieId);
						List<MovieToday> todays = todayMapper.selectByExample(ex);
						
						MovieToday mt = new MovieToday();
						mt.setMovieId(movieId);
						mt.setVersion(version);
						mt.setSortIndex(++count);
						if(todays.size() > 0){
							//update
							mt.setId(todays.get(0).getId());							
							todayMapper.updateByPrimaryKey(mt);
						}else{
							//insert
							mt.setId(UUID.randomUUID().toString());
							todayMapper.insert(mt);
						}
					}
				}
				
				session.commit();
			} finally {
				session.close();
			}			
		}
		return count;
	}
	
		
	/**
	 * add/update to movie_week table
	 * 5页 * 50 = 250条
	 * @return
	 */
	public static int updateWeeklyMusics(){
		int count = 0;
		int offset = 0;
		for (int i = 0; i < 5; i++) {
			String url = StringUtils.format(VIDEO_URL_FORMAT, POPULAR_WEEK, offset);
			offset += LIMIT;
			
			//只取movie的id
			List<Movie> movies = grabVideos(url, false);
			SqlSession session = DefaultDBHelper.getBatchSqlSession();
			MovieMapper movieMapper = session.getMapper(MovieMapper.class);
			MovieWeekMapper weekMapper = session.getMapper(MovieWeekMapper.class);
			Date version = DateUtils.getNow();
			
			try {
				for (Movie movie : movies) {
					String movieId = movie.getId();
					Movie temp = movieMapper.selectByPrimaryKey(movieId);
					if(temp != null){
						QueryExample ex = new QueryExample();
						ex.or().addCriterion("movie_id=", movieId);
						List<MovieWeek> weeks = weekMapper.selectByExample(ex);
						
						MovieWeek mt = new MovieWeek();
						mt.setMovieId(movieId);
						mt.setVersion(version);
						mt.setSortIndex(++count);
						if(weeks.size() > 0){
							//update
							mt.setId(weeks.get(0).getId());
							weekMapper.updateByPrimaryKey(mt);
						}else{
							//insert
							mt.setId(UUID.randomUUID().toString());
							weekMapper.insert(mt);
						}
					}
				}
				
				session.commit();
			} finally {
				session.close();
			}			
		}
		return count;
	}
	
	/**
	 * add/update to recent_movie table
	 * 5页 * 50 = 250条
	 * @return
	 */
	public static int updateRecentMusics(){
		int count = 0;
		int offset = 0;
		for (int i = 0; i < 5; i++) {
			String url = StringUtils.format(VIDEO_URL_FORMAT, POPULAR_RECENT, offset);
			offset += LIMIT;
			
			//只取movie的id
			List<Movie> movies = grabVideos(url, false);
			SqlSession session = DefaultDBHelper.getBatchSqlSession();
			MovieMapper movieMapper = session.getMapper(MovieMapper.class);
			RecentMovieMapper recentMapper = session.getMapper(RecentMovieMapper.class);
			Date version = DateUtils.getNow();
			
			try {
				for (Movie movie : movies) {
					String movieId = movie.getId();
					Movie temp = movieMapper.selectByPrimaryKey(movieId);
					if(temp != null){
						QueryExample ex = new QueryExample();
						ex.or().addCriterion("movie_id=", movieId);
						List<RecentMovie> recents = recentMapper.selectByExample(ex);
						
						RecentMovie mt = new RecentMovie();
						mt.setMovieId(movieId);
						mt.setVersion(version);
						mt.setSortIndex(++count);
						if(recents.size() > 0){
							//update
							mt.setId(recents.get(0).getId());
							recentMapper.updateByPrimaryKey(mt);
						}else{
							//insert
							mt.setId(UUID.randomUUID().toString());
							recentMapper.insert(mt);
						}
					}
				}
				
				session.commit();
			} finally {
				session.close();
			}			
		}
		return count;
	}
	
	private static int grabAndUpdateGenres(String genre, int offset) {
		String url = StringUtils.format(VIDEO_GENRE_URL_FORMAT, genre, offset);
		//不需要详情, 只返回 movie的id
		List<Movie> movies = grabVideos(url, false);
		int size = movies.size();
		if(size > 0){
			//修正genre
			String realGenre = VevoMusicGenres.remendGenre(genre);
			SqlSession session = DefaultDBHelper.getBatchSqlSession();
			MovieMapper movieMapper = session.getMapper(MovieMapper.class);
			MovieGenreMapper mgMapper = session.getMapper(MovieGenreMapper.class);
			try {
				//update movie_genre, movie table's genre field			
				for (Movie movie : movies) {
					String movieId = movie.getId();
					Movie temp = movieMapper.selectByPrimaryKey(movieId);
					if(temp != null){
						QueryExample ex = new QueryExample();
						ex.or().addCriterion("movie_id=", movieId)
								.addCriterion("genre_name=", realGenre);
						boolean ref = mgMapper.countByExample(ex) > 0;
						if( ! ref){
							String updateGenre = null;
							if(temp.getGenre() != null){
								updateGenre = temp.getGenre() + "," + realGenre;
							}else{
								updateGenre = realGenre;
							}
							movieMapper.updateGenre(movieId, updateGenre);
							
							MovieGenre movieGenre = new MovieGenre();
							movieGenre.setId(UUID.randomUUID().toString());
							movieGenre.setMovieId(movieId);
							movieGenre.setGenreName(realGenre);
							
							mgMapper.insert(movieGenre);
						}
					}
				}	
				
				session.commit();
			} finally {
				session.close();
			}					
		}
		
		return size;
	}
	
	

	private static int grabAndSaveVideos(String order, int offset, int index) {
		String url = StringUtils.format(VIDEO_URL_FORMAT, order, offset);
		List<Movie> movies = grabVideos(url, true);
		MovieDao.saveOrUpdate(movies, index);
		return movies.size();
	}

	private static List<Movie> grabVideos(String url, boolean withDetail) {	
		HttpURLConnection conn = null;
		InputStreamReader reader = null;
		JsonObject jsonObject = null;
		try {
			URL uri = new URL(url);
			conn = (HttpURLConnection) uri.openConnection();
			conn.connect();
			reader = new InputStreamReader(conn.getInputStream(), AppEnvironment.charsetName);
			JsonParser parser = new JsonParser();
			jsonObject = (JsonObject) parser.parse(reader);
		} catch (IOException e) {
			logger.error("error happen when fetch vevo json: ", e);
		} finally {			
			try {
				if(reader != null){
					reader.close();
				}
				if(conn != null){
					conn.disconnect();
				}
			} catch (Exception e2) {					
			}					
		}
		
		List<Movie> movies = new ArrayList<Movie>();
		if (jsonObject != null) {
			JsonArray result = jsonObject.getAsJsonArray("result");
			for (int i = 0; i < result.size(); i++) {				
				Movie item = parseJson2Movie((JsonObject) result.get(i), withDetail);
				movies.add(item);		
			}
		}
		return movies;
	}

	private static Movie parseJson2Movie(JsonObject jsonObject, boolean withDetails) {
		Movie item = new Movie();
		String isrc = jsonObject.get("isrc").getAsString();
		item.setVideoId(isrc);				
		// "vo" + videoId
		item.setId(SiteConstants.ID_PREFIX_VEVO + isrc);
		
		if(withDetails){
			item.setWebsite(SiteConstants.WEBSITE_VEVO);
			item.setMovieType(Movie.TYPE_MUSIC);
			item.setDescription("");
			item.setDirector("");
			item.setDuration(jsonObject.get("duration_in_seconds").getAsInt());	
			
			item.setPublishTime(null);
			item.setScore(BigDecimal.ZERO);
			item.setThumbnail(jsonObject.get("image_url").getAsString());
			String title = jsonObject.get("title").getAsString();
			item.setTitle(title);
			//首字母
			item.setTitleInitial(StringUtils.getInitial(title));
			item.setUploader("");
			item.setViewCount(jsonObject.get("viewcount").getAsInt());
			item.setAllowEmbed(0);

			JsonArray artists = jsonObject.getAsJsonArray("artists_main");
			StringBuilder sbActors = new StringBuilder();
			for (int j = 0; j < artists.size(); j++) {
				JsonObject artist = artists.get(j).getAsJsonObject();
				String actor = artist.get("name").getAsString();
				if (j > 0) {
					sbActors.append(",");
				}
				sbActors.append(actor);
			}
			item.setActors(sbActors.toString());
			
			if (artists.size() == 1) {
				JsonObject artist = artists.get(0).getAsJsonObject();
				String artistsUrl = artist.get("url_safename").getAsString();
				String nameUrl = jsonObject.get("url_safe_title").getAsString();
				String url = StringUtils.format("http://www.vevo.com/watch/{}/{}/{}", artistsUrl, nameUrl, isrc);
				item.setItemUrl(url);
			} else {
				item.setItemUrl("http://www.vevo.com/video/" + isrc);
			}
		}	
		
		return item;
	}
}
